package com.withyou.baidusave;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.google.gson.Gson;
import com.withyou.baidusave.util.CmdLineUtil;

public class StartSaveShell {

	private static String durl = "https://pan.baidu.com/share/transfer?shareid=%s&from=%s&ondup=newcopy&async=1&channel=chunlei&web=1&app_id=%s&bdstoken=%s&logid=MTU2OTA3MTgyNTcwOTAuNDM3MjQwMjM1NzIxNzA0NDU&clienttype=0";
	
	//验证验证码地址
	private static String lurl =  "https://pan.baidu.com/share/verify?surl=%s&t=%s&channel=chunlei&web=1&app_id=%s&bdstoken=%s&logid=MTU2OTA3MTgyNTcwOTAuNDM3MjQwMjM1NzIxNzA0NDU&clienttype=0";
	
	//文件列表
	private static String fileurl = "https://pan.baidu.com/share/list?uk=%s&shareid=%s&order=other&desc=1&showempty=0&web=1&page=1&num=100&dir=%s&channel=chunlei&web=1&app_id=%s&bdstoken=%s&logid=MTU2OTA3MTgyNTcwOTAuNDM3MjQwMjM1NzIxNzA0NDU&clienttype=0";
	
	
	
	//创建目录
	private static String createurl = "https://pan.baidu.com/api/create?a=commit&channel=chunlei&web=1&app_id=%s&bdstoken=%s&logid=MTU2OTA3MTgyNTcwOTAuNDM3MjQwMjM1NzIxNzA0NDU&clienttype=0";
	
	//------------------登录逻辑未实现，需要自行登录漏填写-----------------------
	//1.云盘主目录新建/文件目录
	//2.登录后获取如下属性
	//3.处理百度云文件信息
	//appid(必填)
	private static String appId = "";
	
	//登录uk(必填)
	private static String uk = "";
	
	//登录token(必填)
	private static String loginToken = "";
	
	//登录cookies(必填)  移除BAIDUID BDCLND
	private static String logincookies = ""; 
		
	private static String environment = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36";
	
	public static UserInfo parsHtml(String html){
		Pattern pattern = Pattern.compile("yunData.setData\\(\\{((\\D*)(\\d+)(.*))\\}\\);");
		Matcher matcher = pattern.matcher(html);
		StringBuffer buffer = new StringBuffer();
		buffer.append("{");
		while(matcher.find()){
			buffer.append(matcher.group(1));
		}
		buffer.append("}");
		Gson gson = new Gson();
		UserInfo user = gson.fromJson(buffer.toString(), UserInfo.class);
		return user;
	}
	
	/**
	 * 自动保存
	 * @param user
	 */
	public static void autoSave(UserInfo user,List<UserInfo> uuuu){
		CloseableHttpClient httpClient = HttpClientBuilder.create().build();
		// 创建Post请求
		String url = String.format(durl, user.getShareid(), user.getUk(), appId, user.getBdstoken());
		HttpPost httpPost = new HttpPost(url);
	
		httpPost.setHeader("User-Agent", environment);
		httpPost.setHeader("Referer",user.getUrl());
		
		//抓取文件目录下的所有文件列表
		Filelist filelist = user.getFile_list();
		StringBuffer bf = new StringBuffer();
		if(filelist != null && filelist.getList().size() >0){
			List<String> fl = filelist.getList().stream().map((item0)->{
				return item0.getFs_id();
			}).collect(Collectors.toList());
			bf.append("[");
			bf.append(StringUtils.join(fl, ","));
			bf.append("]");
		}

		//2、封装请求参数
		List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
		list.add(new BasicNameValuePair("shareid", user.getShareid()));
		list.add(new BasicNameValuePair("from", user.getUk()));
		list.add(new BasicNameValuePair("app_id", appId));
		list.add(new BasicNameValuePair("bdstoken", user.getBdstoken()));
		//分享文件列表
		list.add(new BasicNameValuePair("fsidlist", bf.toString()));
		//存储的文件路径
		list.add(new BasicNameValuePair("path", user.getPath()));
		
		//3、转化参数
		UrlEncodedFormEntity refe = new UrlEncodedFormEntity(list,Consts.UTF_8);
		httpPost.setHeader("Cookie",user.getCookie());
		httpPost.setEntity(refe);
		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpPost);
			if(response.getStatusLine().getStatusCode() == 200){
				HttpEntity responseEntity = response.getEntity();
				if (responseEntity != null) {
					String result = EntityUtils.toString(responseEntity,Charset.forName("UTF-8"));
					System.out.println(user.getUrl()+">>"+result);
					SaveResult re = new Gson().fromJson(result, SaveResult.class);
					//解决vip限制，分解保存
					if(re != null && "12".equals(re.getErrno())){
						//1.拉取父目录下的子目录列表
						List<Filelist> fList = getFilelist(user);
						if(fList != null){
							//遍历所有父目录查询到的子目录
							for (Filelist filelist2 : fList) {

								filelist2.getList().forEach((iten)->{
									Filelist fileltemp = new Filelist();
									fileltemp.setList(new ArrayList<FileListItem>());
									fileltemp.getList().add(iten);
									user.setFile_list(fileltemp);
									String path2 = iten.getPath();
									//常见目录
									String remo = path2.split("/")[1];
									user.setPath("/文件"+path2.replace("/"+remo, ""));
								
									createDIr(user);
									autoSave( user, uuuu);
								});
								
							}
						}
					}
				}	
			}else{
				System.out.println(user.getUrl()+"调用>>"+response.getStatusLine().getStatusCode());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				// 释放资源
				if (httpClient != null) {
					httpClient.close();
				}
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	
	
	public static void createDIr(UserInfo user){
		CloseableHttpClient httpClient = HttpClientBuilder.create().build();
		// 创建Post请求
		String url = String.format(createurl, appId, user.getBdstoken());
		HttpPost httpPost = new HttpPost(url);
	
		httpPost.setHeader("User-Agent", environment);
		httpPost.setHeader("Referer",user.getUrl());
		
		

		//2、封装请求参数
		List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
		list.add(new BasicNameValuePair("a", "commit"));
		list.add(new BasicNameValuePair("from", user.getUk()));
		list.add(new BasicNameValuePair("app_id", appId));
		list.add(new BasicNameValuePair("bdstoken", user.getBdstoken()));
		list.add(new BasicNameValuePair("web", "1"));
		list.add(new BasicNameValuePair("channel", "chunlei"));
		list.add(new BasicNameValuePair("clienttype", "0"));
		list.add(new BasicNameValuePair("path", user.getPath()));
		list.add(new BasicNameValuePair("isdir", "1"));
		list.add(new BasicNameValuePair("block_list", "[]"));

		//分享文件列
		//存储的文件路径
		list.add(new BasicNameValuePair("path", user.getPath()));
		//3、转化参数
		UrlEncodedFormEntity refe = new UrlEncodedFormEntity(list,Consts.UTF_8);
		httpPost.setHeader("Cookie",user.getCookie());
		httpPost.setEntity(refe);
		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpPost);
			if(response.getStatusLine().getStatusCode() == 200){
				HttpEntity responseEntity = response.getEntity();
				if (responseEntity != null) {
					String result = EntityUtils.toString(responseEntity,Charset.forName("UTF-8"));
					System.out.println(user.getUrl()+">>"+result);
				}	
			}else{
				System.out.println(user.getUrl()+"调用>>"+response.getStatusLine().getStatusCode());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				// 释放资源
				if (httpClient != null) {
					httpClient.close();
				}
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 返回父目录下所有目录对应的子目录
	 * @param user
	 * @return
	 */
    public static List<Filelist> getFilelist(UserInfo user){
    	 List<Filelist> res = new ArrayList<Filelist>();
    
		// 创建Post请求
    	user.getFile_list().getList().forEach((item)->{
    		CloseableHttpClient httpClient = HttpClientBuilder.create().build();
    		String parent = item.getFs_id();
    		String path = item.getPath();
    		String name = item.getServer_filename();
    		String fileurl1 = "";
    		try {
    			fileurl1 = java.net.URLEncoder.encode(path, "UTF-8");
			} catch (Exception e) {
				 e.printStackTrace();
			}
    		String url = String.format(fileurl, user.getUk(), user.getShareid(), fileurl1 , appId, user.getBdstoken());
    		HttpPost httpPost = new HttpPost(url);
    		
    		httpPost.setHeader("User-Agent", environment);
    		httpPost.setHeader("Referer",user.getUrl());
    		

    		//2、封装请求参数
    		List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
    		list.add(new BasicNameValuePair("shareid", user.getShareid()));
    		list.add(new BasicNameValuePair("app_id", appId));
    		list.add(new BasicNameValuePair("order", "other"));
    		list.add(new BasicNameValuePair("desc", "1"));
    		list.add(new BasicNameValuePair("uk", uk));
    		list.add(new BasicNameValuePair("bdstoken", user.getBdstoken()));
    		
    		list.add(new BasicNameValuePair("showempty", "0"));
    		list.add(new BasicNameValuePair("web", "1"));
    		list.add(new BasicNameValuePair("page", "1"));
    		list.add(new BasicNameValuePair("num", "100"));
    		list.add(new BasicNameValuePair("dir", path));
    		list.add(new BasicNameValuePair("channel", "chunlei"));
    		list.add(new BasicNameValuePair("clienttype", "0"));
    		list.add(new BasicNameValuePair("showempty", "0"));
    		//3、转化参数
    		UrlEncodedFormEntity refe = new UrlEncodedFormEntity(list,Consts.UTF_8);
    		httpPost.setHeader("Cookie",user.getCookie());
    		httpPost.setEntity(refe);
    		CloseableHttpResponse response = null;
    		try {
    			response = httpClient.execute(httpPost);
    			if(response.getStatusLine().getStatusCode() == 200){
    				HttpEntity responseEntity = response.getEntity();
    				if (responseEntity != null) {
    					String result = EntityUtils.toString(responseEntity,Charset.forName("UTF-8"));
    					Filelist re = new Gson().fromJson(result, Filelist.class);
    					re.setPath(path);
    					res.add(re);
    				}	
    			}else{
    				System.out.println(user.getUrl()+"调用>>"+response.getStatusLine().getStatusCode());
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}finally {
    			try {
    				// 释放资源
    				if (httpClient != null) {
    					httpClient.close();
    				}
    				if (response != null) {
    					response.close();
    				}
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		
    	});
    	return res;
    }
    
	/**
	 * start
	 * @param args
	 * @throws ParseException
	 * @throws IOException
	 */
	public static void main(String[] args) throws ParseException, IOException {
		Options options = CmdLineUtil.buildCommandlineOptions(new Options());
		CommandLine commandLine = CmdLineUtil.parseCmdLine("startshell", args, options, new PosixParser());
        String path = "C:\\Users\\Administrator\\git\\BaiDuYunAutoSaveShell\\doc\\百度云盘内容.txt";
        if(commandLine.hasOption("f")){
        	  path = commandLine.getOptionValue("f");
        }
        //从配置文件读取
        if (commandLine.hasOption('c')) {
            String file = commandLine.getOptionValue('c');
            if (file != null) {
                InputStream in = new BufferedInputStream(new FileInputStream(file));
                Properties properties = new Properties();
                properties.load(in);
                appId = properties.getProperty("appId");
                appId = properties.getProperty("uk");
                appId = properties.getProperty("loginToken");
                appId = properties.getProperty("logincookies");
                System.out.printf("load config properties file OK, %s%n", file);
                in.close();
            }
        }else{
        	   if(commandLine.hasOption("appId")){
           	      appId = commandLine.getOptionValue("appId");
	           }
	           if(commandLine.hasOption("uk")){
	           	  uk = commandLine.getOptionValue("uk");
	           }
	           if(commandLine.hasOption("loginToken")){
	           	  loginToken = commandLine.getOptionValue("loginToken");
	           }
	           if(commandLine.hasOption("logincookies")){
	           	  logincookies = commandLine.getOptionValue("logincookies");
	           }
        }

        if(StringUtils.isEmpty(path) || StringUtils.isEmpty(appId) || StringUtils.isEmpty(uk) || StringUtils.isEmpty(loginToken) || StringUtils.isEmpty(logincookies)){
        	System.out.println("缺失必要参数");
        	System.exit(-1);
        }
//		//1.读取文件
		List<String> lines = FileUtil.readFileLine(path);
//		//2.构造BaiDuYunItemInfo
		List<BaiDuYunItemInfo> iteminfo = new ArrayList<BaiDuYunItemInfo>();
		for (String line : lines) {
			try {
				if(line.contains("链接：")){//2.1.提取相关信息
					BaiDuYunItemInfo it = new BaiDuYunItemInfo();
					it.setUrl(line.split("：")[1]);
					iteminfo.add(it);
				}else if(line.contains("提取码：")){
					BaiDuYunItemInfo it = iteminfo.get(iteminfo.size()-1);
					it.setCode(line.split("：")[1]);
				}
			} catch (Exception e) {}
		}
//		BaiDuYunItemInfo i = new BaiDuYunItemInfo();
//		i.setUrl("https://pan.baidu.com/s/1aNXdxWWiaEA65y9G0iweSA");
//		i.setCode("7a38");
//		iteminfo.add(i);
		//3.获取百度云信息
		getBaiDuYunItemInfos(iteminfo);
		
		
		Runtime.getRuntime().addShutdownHook(new Thread("任务完成"){
		    @Override
		    public void run() {
		        //资源释放动作
		    	System.out.println("执行完成");
		    }
		});
	}
	
	@SuppressWarnings("resource")
	private static void getBaiDuYunItemInfos(List<BaiDuYunItemInfo> iteminfo){
		List<UserInfo> uuuu = new ArrayList<UserInfo>();
		for (BaiDuYunItemInfo info : iteminfo) {
			// 创建Post请求
 			CloseableHttpClient httpClient = HttpClientBuilder.create().build();
			HttpPost httpPost = new HttpPost(info.getUrl().trim());
			CloseableHttpResponse response = null;
			try {
				response = httpClient.execute(httpPost);
				HttpEntity responseEntity = null;
				if(response.getStatusLine().getStatusCode() == 200){
					getCookies(info);//获取cookies到info
					response = httpClient.execute(httpPost);
					if(response.getStatusLine().getStatusCode() == 200){
						responseEntity = response.getEntity();
						if (responseEntity != null) {
							UserInfo user = parsHtml(EntityUtils.toString(responseEntity,Charset.forName("UTF-8")));
							user.setUrl(info.getUrl().trim());
							user.setCookie(info.getCoke());
							autoSave(user,uuuu);//保存数据
						}
					}else{
						System.out.println(info.getUrl().trim()+"查询>>"+response.getStatusLine().getStatusCode());
					}
					
				}else{
					if(response.getStatusLine().getStatusCode() == 302){
						Header[] header = response.getHeaders("Location");
						info.setUrl(header[0].getValue().trim());//拿到302地址
						getCookies(info);//获取cookies到info
						httpPost.setHeader("Cookie",info.getCoke());
						response = httpClient.execute(httpPost);
						if(response.getStatusLine().getStatusCode() == 200){
							responseEntity = response.getEntity();
							if (responseEntity != null) {
								UserInfo user = parsHtml(EntityUtils.toString(responseEntity,Charset.forName("UTF-8")));
								user.setUrl(info.getUrl().trim());
								user.setCookie(info.getCoke());
								autoSave(user,uuuu);//保存数据
							}
						}else{
							System.out.println(info.getUrl().trim()+"查询>>"+response.getStatusLine().getStatusCode());
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				try {
					// 释放资源
					if (httpClient != null) {
						httpClient.close();
					}
					if (response != null) {
						response.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	
	}
    
	
	/**
	 * 获取cookies信息
	 * @param info
	 */
	private static void getCookies(BaiDuYunItemInfo info){
		String path = info.getUrl();
		path = path.replace("https://pan.baidu.com/share/init?surl=", "");
		//1.通过验证码获取分享内容
		String url = String.format(lurl, path, System.currentTimeMillis(), appId, loginToken);
		BasicCookieStore cookieStore = new BasicCookieStore();
		CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build();
		HttpPost httpPost = new HttpPost(url);
		List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
		list.add(new BasicNameValuePair("pwd",info.getCode()));//验证码
		list.add(new BasicNameValuePair("surl", path));
		list.add(new BasicNameValuePair("t", System.currentTimeMillis()+""));
		list.add(new BasicNameValuePair("app_id", appId));
		list.add(new BasicNameValuePair("bdstoken", loginToken));
		UrlEncodedFormEntity refe = new UrlEncodedFormEntity(list,Consts.UTF_8);
		httpPost.setEntity(refe);
		HttpClientContext context = HttpClientContext.create();
		httpPost.setHeader("User-Agent", environment);
		httpPost.setHeader("Referer",path);
		CloseableHttpResponse response = null;
		try {
			response = httpClient.execute(httpPost,context);
			if(response.getStatusLine().getStatusCode() == 200){
				 String logincookiess = logincookies;
				 for (Cookie c : cookieStore.getCookies()) {
					 logincookiess += ";"+c.getName()+"="+c.getValue();
			     }
				 info.setCoke(logincookiess);
			}else{
				Header[] header = response.getHeaders("Location");
				System.out.println("获取cookis>>302-"+header[0].getValue().trim());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				// 释放资源
				if (httpClient != null) {
					httpClient.close();
				}
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
